<script setup lang="ts">
import { ref, watchEffect, nextTick, onMounted, watch, onBeforeUnmount } from "vue"
import { getImgUrl } from "#/utils/getImgUrl"
import type { TempTextConfig } from "./types"
import { cloneDeep } from '@vben/utils';

defineOptions({ name: 'template-draw-canvas' })

const props = defineProps<{
  templateFile: string
  tempTextConfigs: TempTextConfig[]
}>()

const emit = defineEmits<{
  'update:tempTextConfigs': [configs: TempTextConfig[]]
  'update:canvasInfo': [info: {devicePixelRatio: number, scaleX: number, scaleY: number, canvasImgWidth: number, canvasImgHeight: number, imgWidth: number, imgHeight: number}]
}>()
// 获取设备像素比
const devicePixelRatio = ref(window.devicePixelRatio || 1)
const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D>()
const refSrc = ref('')
const imgLoaded = ref(false)
const imgLoading = ref(false)
const backgroundImage = ref<HTMLImageElement>()
const canvasWidth = ref(800)
const canvasHeight = ref(650)
const imageRect = ref({ x: 0, y: 0, width: 0, height: 0 })
const tempTextConfigs = ref<TempTextConfig[]>([])

// 拖拽相关状态
const isDragging = ref(false)
const dragStartPos = ref({ x: 0, y: 0 })
const dragStartConfig = ref<TempTextConfig | null>(null)
const hoveredTextIndex = ref(-1)
const currentMousePos = ref({ x: 0, y: 0 })

function arrayBufferToImageBase64(buffer: ArrayBuffer, mimeType: string = 'image/png'): string {
  const bytes = new Uint8Array(buffer)
  let binary = '';
  bytes.forEach(byte => binary += String.fromCharCode(byte))
  return `data:${mimeType};base64,${btoa(binary)}`
}

async function loadImage() {
  try {
    imgLoading.value = true
    const src = await getImgUrl(props.templateFile) as any
    const base64Content = arrayBufferToImageBase64(src)
    const img = new Image()
    refSrc.value = base64Content
    img.src = base64Content
    img.crossOrigin = 'anonymous'
    img.onload = () => {
      backgroundImage.value = img
      imgLoaded.value = true
      imgLoading.value = false
      nextTick(() => {
        initCanvas()
      })
    };
    img.onerror = () => {
      imgLoaded.value = false
      imgLoading.value = false
    };
  } catch (error) {
    imgLoading.value = false
  }
}

function initCanvas() {
  if (!canvasRef.value) return
  
  const canvas = canvasRef.value
  ctx.value = canvas.getContext('2d')!
  
  
  // 获取canvas的CSS尺寸
  const rect = canvas.getBoundingClientRect()
  const cssWidth = rect.width
  const cssHeight = rect.height
  
  // 设置canvas的实际尺寸（考虑设备像素比）
  canvas.width = cssWidth * devicePixelRatio.value
  canvas.height = cssHeight * devicePixelRatio.value
  
  // 设置canvas的CSS尺寸
  canvas.style.width = cssWidth + 'px'
  canvas.style.height = cssHeight + 'px'
  
  // 缩放绘图上下文以匹配设备像素比
  ctx.value!.scale(devicePixelRatio.value, devicePixelRatio.value)
  
  // 更新canvas尺寸变量
  canvasWidth.value = cssWidth
  canvasHeight.value = cssHeight
  
  // 计算图片在canvas中的位置和尺寸
  if (backgroundImage.value) {
    const img = backgroundImage.value
    const imgAspectRatio = img.width / img.height
    console.log(imgAspectRatio)
    const canvasAspectRatio = canvasWidth.value / canvasHeight.value
    
    if (imgAspectRatio > canvasAspectRatio) {
      // 图片更宽，以宽度为准
      imageRect.value.width = canvasWidth.value
      imageRect.value.height = imageRect.value.width / imgAspectRatio
    } else {
      // 图片更高，以高度为准
      imageRect.value.height = canvasHeight.value
      imageRect.value.width = imageRect.value.height * imgAspectRatio
    }
    
    // 居中显示
    imageRect.value.x = (canvasWidth.value - imageRect.value.width) / 2
    imageRect.value.y = (canvasHeight.value - imageRect.value.height) / 2
  }
  initTempTextConfigs()
}

function drawCanvas() {
  if (!ctx.value || !backgroundImage.value) return
  
  const canvas = canvasRef.value!
  ctx.value.clearRect(0, 0, canvas.width, canvas.height)
  
  // 绘制背景图片
  ctx.value.drawImage(
    backgroundImage.value,
    imageRect.value.x,
    imageRect.value.y,
    imageRect.value.width,
    imageRect.value.height
  )
  
  // 绘制图片边框
  drawImageBorder()
  
  // 绘制文本配置
  tempTextConfigs.value.forEach((config, index) => {
    drawTextBlock(config, index)
  })
  
  // 绘制基准线（仅在拖拽时显示）
  if (isDragging.value) {
    drawGuidelines()
  }
}

function drawTextBlock(config: TempTextConfig, index: number) {
  if (!ctx.value) return
  
  const { x, y, fontSize, fontColor, fontBold, fontItalic, fontType, alignCenter } = config
  
  // 设置字体样式
  const fontWeight = fontBold ? 'bold' : 'normal'
  const fontStyle = fontItalic ? 'italic' : 'normal'
  ctx.value.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontType}`
  ctx.value.fillStyle = fontColor
  ctx.value.textAlign = alignCenter ? 'center' : 'left'
  ctx.value.textBaseline = 'top'
  
  // 计算实际绘制位置（相对于图片区域）
  let drawX = imageRect.value.x + x
  const drawY = imageRect.value.y + y
  
  // 如果启用居中对齐，计算相对于图片中心的X坐标
  if (alignCenter) {
    const imageCenterX = imageRect.value.x + imageRect.value.width / 2
    drawX = imageCenterX
  }
  
  // 绘制文本
  ctx.value.fillText(config.exampleValue, drawX, drawY)
  
  // 绘制选择框（如果正在拖拽或悬停）
  if (isDragging.value && dragStartConfig.value === config || hoveredTextIndex.value === index) {
    const textMetrics = ctx.value.measureText(config.exampleValue)
    const textWidth = textMetrics.width
    const textHeight = fontSize
    
    // 计算选择框位置
    let selectionX = drawX - 5
    if (alignCenter) {
      selectionX = drawX - textWidth / 2 - 5
    }
    
    ctx.value.strokeStyle = '#007bff'
    ctx.value.lineWidth = 2
    ctx.value.setLineDash([5, 5])
    ctx.value.strokeRect(selectionX, drawY - 5, textWidth + 10, textHeight + 10)
    ctx.value.setLineDash([])
  }
}

function getMousePos(event: MouseEvent) {
  if (!canvasRef.value) return { x: 0, y: 0 }
  
  const rect = canvasRef.value.getBoundingClientRect()
  
  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top
  }
}

function drawImageBorder() {
  if (!ctx.value) return
  
  const context = ctx.value
  
  // 设置边框样式
  context.strokeStyle = '#666666'
  context.lineWidth = 1
  context.setLineDash([1, 4])
  
  // 绘制图片边框
  context.strokeRect(
    imageRect.value.x,
    imageRect.value.y,
    imageRect.value.width,
    imageRect.value.height
  )
  
  // 重置线条样式
  context.setLineDash([])
}

function drawGuidelines() {
  if (!ctx.value || !isDragging.value || !dragStartConfig.value) return
  
  const context = ctx.value
  const mouseX = currentMousePos.value.x
  const mouseY = currentMousePos.value.y
  
  // 设置对齐线样式
  context.lineWidth = 1
  context.setLineDash([5, 5])
  
  // 计算图片中心点
  const imageCenterX = imageRect.value.x + imageRect.value.width / 2
  const imageCenterY = imageRect.value.y + imageRect.value.height / 2
  
  // 绘制与其他文本区块的对齐线
  tempTextConfigs.value.forEach((config) => {
    if (config === dragStartConfig.value) return
    
    let configX = imageRect.value.x + config.x
    const configY = imageRect.value.y + config.y
    
    // 如果启用居中对齐，使用图片中心X坐标
    if (config.alignCenter) {
      configX = imageRect.value.x + imageRect.value.width / 2
    }
    
    // 水平对齐线（Y坐标相同）
    if (Math.abs(mouseY - configY) < 10) {
      context.strokeStyle = '#4ecdc4'
      context.beginPath()
      context.moveTo(imageRect.value.x, configY)
      context.lineTo(imageRect.value.x + imageRect.value.width, configY)
      context.stroke()
    }
    
    // 垂直对齐线（X坐标相同）
    if (Math.abs(mouseX - configX) < 10) {
      context.strokeStyle = '#4ecdc4'
      context.beginPath()
      context.moveTo(configX, imageRect.value.y)
      context.lineTo(configX, imageRect.value.y + imageRect.value.height)
      context.stroke()
    }
  })
  
  // 绘制中心线
  const snapDistance = 10
  
  // 垂直中心线
  if (Math.abs(mouseX - imageCenterX) < snapDistance) {
    context.strokeStyle = '#ff9ff3'
    context.beginPath()
    context.moveTo(imageCenterX, imageRect.value.y)
    context.lineTo(imageCenterX, imageRect.value.y + imageRect.value.height)
    context.stroke()
  }
  
  // 水平中心线
  if (Math.abs(mouseY - imageCenterY) < snapDistance) {
    context.strokeStyle = '#ff9ff3'
    context.beginPath()
    context.moveTo(imageRect.value.x, imageCenterY)
    context.lineTo(imageRect.value.x + imageRect.value.width, imageCenterY)
    context.stroke()
  }
  
  // 重置线条样式
  context.setLineDash([])
}

function isPointInTextBlock(x: number, y: number, config: TempTextConfig): boolean {
  if (!ctx.value) return false
  
  let drawX = imageRect.value.x + config.x
  const drawY = imageRect.value.y + config.y
  
  // 如果启用居中对齐，计算相对于图片中心的X坐标
  if (config.alignCenter) {
    const imageCenterX = imageRect.value.x + imageRect.value.width / 2
    drawX = imageCenterX
  }
  
  ctx.value.font = `${config.fontItalic ? 'italic' : 'normal'} ${config.fontBold ? 'bold' : 'normal'} ${config.fontSize}px ${config.fontType}`
  const textMetrics = ctx.value.measureText(config.exampleValue)
  const textWidth = textMetrics.width
  const textHeight = config.fontSize
  
  // 计算选择框位置
  let selectionX = drawX - 5
  if (config.alignCenter) {
    selectionX = drawX - textWidth / 2 - 5
  }
  
  return x >= selectionX && x <= selectionX + textWidth + 10 &&
         y >= drawY - 5 && y <= drawY + textHeight + 5
}

function findTextBlockAtPosition(x: number, y: number): number {
  for (let i = tempTextConfigs.value.length - 1; i >= 0; i--) {
    const config = tempTextConfigs.value[i]
    if (config && isPointInTextBlock(x, y, config)) {
      return i
    }
  }
  return -1
}

function handleMouseDown(event: MouseEvent) {
  const mousePos = getMousePos(event)
  const textIndex = findTextBlockAtPosition(mousePos.x, mousePos.y)
  
  if (textIndex !== -1) {
    const config = tempTextConfigs.value[textIndex]
    if (config) {
      isDragging.value = true
      dragStartPos.value = mousePos
      dragStartConfig.value = config
      canvasRef.value!.style.cursor = 'grabbing'
    }
  }
}

function handleMouseMove(event: MouseEvent) {
  const mousePos = getMousePos(event)
  currentMousePos.value = mousePos
  
  if (isDragging.value && dragStartConfig.value) {
    // 计算拖拽偏移量
    const deltaX = mousePos.x - dragStartPos.value.x
    const deltaY = mousePos.y - dragStartPos.value.y
    
    // 计算新位置
    let newX = dragStartConfig.value.x + deltaX
    let newY = dragStartConfig.value.y + deltaY
    
    // 计算图片中心点
    const imageCenterX = imageRect.value.width / 2
    const imageCenterY = imageRect.value.height / 2
    
    // 检查是否需要吸附对齐
    const snapDistance = 5 // 吸附距离
    
    // 与其他文本区块对齐
    tempTextConfigs.value.forEach((config) => {
      if (config === dragStartConfig.value) return
      
      // 水平对齐吸附
      if (Math.abs(newY - config.y) < snapDistance) {
        newY = config.y
      }
      
      // 垂直对齐吸附
      if (Math.abs(newX - config.x) < snapDistance) {
        newX = config.x
      }
    })
    
    // 与中心点对齐
    if (Math.abs(newX - imageCenterX) < snapDistance) {
      newX = imageCenterX
    }
    if (Math.abs(newY - imageCenterY) < snapDistance) {
      newY = imageCenterY
    }
    
    // 更新配置数组
    const updatedConfigs = cloneDeep(tempTextConfigs.value)
    const configIndex = updatedConfigs.findIndex((config: TempTextConfig) => config.fieldName === dragStartConfig.value?.fieldName)
    
    if (configIndex !== -1 && dragStartConfig.value) {
      updatedConfigs[configIndex] = {
        ...dragStartConfig.value,
        x: Number(newX.toFixed(0)),
        y: Number(newY.toFixed(0))
      }
      tempTextConfigs.value = updatedConfigs
    }
    
    drawCanvas()
  } else {
    // 更新悬停状态
    const textIndex = findTextBlockAtPosition(mousePos.x, mousePos.y)
    if (textIndex !== hoveredTextIndex.value) {
      hoveredTextIndex.value = textIndex
      drawCanvas()
    }
    
    // 更新鼠标样式
    if (textIndex !== -1) {
      canvasRef.value!.style.cursor = 'grab'
    } else {
      canvasRef.value!.style.cursor = 'default'
    }
  }
}

function handleMouseUp() {
  if (isDragging.value) {
    isDragging.value = false
    dragStartConfig.value = null
    canvasRef.value!.style.cursor = 'default'
    emit('update:tempTextConfigs', tempTextConfigs.value)
  }
}

function redraw() {
  if (imgLoaded.value) {
    drawCanvas()
  }
}

function initTempTextConfigs() {
  if (tempTextConfigs.value.length === 0) {
    if (!backgroundImage.value) return
    const img = backgroundImage.value
    const { width: canvasImgWidth, height: canvasImgHeight } = imageRect.value
    
    console.log('原始图片尺寸:', img.width, img.height)
    console.log('Canvas中图片尺寸:', canvasImgWidth, canvasImgHeight)
    
    // 计算缩放比例
    const scaleX = canvasImgWidth / img.width
    const scaleY = canvasImgHeight / img.height
    const tConfigs = cloneDeep(props.tempTextConfigs)
    tempTextConfigs.value = tConfigs.map((item) => ({
      ...item,
      // x坐标按比例缩放
      x: Number((item.x * scaleX).toFixed(0)),
      // y坐标翻转并缩放：height - y * scaleY
      y: Number((canvasImgHeight + devicePixelRatio.value - (item.y + item.fontSize) * scaleY).toFixed(0)),
      // 字体大小按比例缩放
      fontSize: Number((item.fontSize * Math.min(scaleX, scaleY)).toFixed(0))
    }))
    // test
    drawCanvas()
    emit('update:tempTextConfigs', tempTextConfigs.value)
    emit('update:canvasInfo', { devicePixelRatio: devicePixelRatio.value, scaleX, scaleY, canvasImgWidth, canvasImgHeight, imgWidth: img.width, imgHeight: img.height })
  }
}

// 监听配置变化
watch(() => props.tempTextConfigs, () => {
  if (imgLoaded.value) {
    console.log('配置变化')
    tempTextConfigs.value = cloneDeep(props.tempTextConfigs)
    drawCanvas()
  }
}, { deep: true })

watchEffect(() => {
  if (props.templateFile) {
    nextTick(() => {
      loadImage()
    })
  }
})

onMounted(() => {
  if (canvasRef.value) {
    canvasRef.value.addEventListener('mousedown', handleMouseDown)
    canvasRef.value.addEventListener('mousemove', handleMouseMove)
    canvasRef.value.addEventListener('mouseup', handleMouseUp)
    canvasRef.value.addEventListener('mouseleave', handleMouseUp)
  }
})
onBeforeUnmount(() => {
  if (canvasRef.value) {
    canvasRef.value.removeEventListener('mousedown', handleMouseDown)
    canvasRef.value.removeEventListener('mousemove', handleMouseMove)
    canvasRef.value.removeEventListener('mouseup', handleMouseUp)
    canvasRef.value.removeEventListener('mouseleave', handleMouseUp)
  }
})

defineExpose({ redraw })
</script>
<template>
  <div v-loading="imgLoading" class="w-full h-full relative">
    <canvas 
      ref="canvasRef"
      class="w-full h-full" 
      id="tempmateView"
    ></canvas>
  </div>
</template>
<style lang="less" scoped>
</style>
